package com.example.emailWeb.Socket.Proxy;

import com.example.emailWeb.ntru.encrypt.NtruProxyServer;
import com.example.emailWeb.ntru.encrypt.NtruProxyUserA;
import com.example.emailWeb.ntru.encrypt.NtruProxyUserB;
import com.example.emailWeb.ntru.polynomial.IntegerPolynomial;
import org.omg.PortableServer.POA;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class ProxyProcess {
    private PolySocketData polySocketData;
    public IntegerPolynomial a, r1, b, Rkab;
    public IntegerPolynomial CA, CB;

    public boolean keyExchange, encry;
    public NtruProxyUserA UserA;
    public NtruProxyUserB UserB;
    public NtruProxyServer Server;
    public Socket socketOfRequest;
//    NtruProxyUserA UserA = new NtruProxyUserA(NtruProxyParameters.APR2011_439);
//    NtruProxyUserB UserB = new NtruProxyUserB(NtruProxyParameters.APR2011_439);
//    NtruProxyServer Server = new NtruProxyServer(NtruProxyParameters.APR2011_439);

    //首先初始化，确定自己的身份

    /**
     * 对于文件的拥有者而言，在初始化的时候，必须把文件请求者的socket放进去，这样才能给他回复消息
     *
     * @param userA
     * @param socketOfRequest
     */
    public ProxyProcess(NtruProxyUserA userA, Socket socketOfRequest) {
        UserA = userA;
        this.socketOfRequest = socketOfRequest;
    }

    public ProxyProcess(NtruProxyUserB userB) {
        UserB = userB;
    }


    public ProxyProcess(NtruProxyServer server) {
        Server = server;
    }
    public void onlyGiveCB2Requester(Socket socket,PolySocketData polySocketData){
        System.out.println("收到CB的请求");
        ObjectOutputStream os = null;
        try {
            os =  new ObjectOutputStream(socket.getOutputStream());
            PolySocketData polySocketData1 = new PolySocketData(polySocketData);
            polySocketData1.CB = CB;
            os.writeObject(polySocketData1);
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(os!=null)
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void Main(PolySocketData polySocketData) throws IOException {
        //密钥协商
        if (polySocketData.keyExchange) {
            System.out.println("密钥协商");
            /**
             * 作为文件的拥有者
             * 1. 接收B发来的data
             * 2. 生成a,r
             * 3. 把a发给b，把r发给服务器
             */
            if (UserA != null) {
                //这个data是文件的请求者发过来的吗?
                if (polySocketData.requester) {
                    IntegerPolynomial a = UserA.a;
                    IntegerPolynomial r1 = UserA.r1;
                    //发送多项式
                    sendAR1(polySocketData, a, r1);

                }
                return;
            }

            /**
             * 文件请求者的处理
             * 通过a生成b,把b发给服务器
             * 不需要等待服务器返回CB，发完直接断开socket即可;因为CB由服务器发送到邮箱
             *
             * 文件请求者，需要保存自己的密钥参数，便于以后收到CB之后，通过CB解密出m
             */
            if (UserB != null) {
                //文件所有者发来的data
                if (polySocketData.fileOwner) {
                    System.out.println("接收方已确定: " + polySocketData.fileOwner);
                    if (a != null) {
                        UserB.receiveA(polySocketData.a);
                        System.out.println("b已经生成: " + UserB.b);
                        RequesterSend2Server(polySocketData, UserB.b);
                    }
                }
                return;
            }

            /**
             * 服务器的处理
             * 1. 接收文件拥有者发来的r1
             * 2. 接收文件请求者发来的b，通过r,b生成RKab
             * 3. 接收文件拥有者发来的CA，通过CA生成CB，把用户请求的文件和CB一起投递到用户的邮箱
             */
            if (Server != null) {
                if (polySocketData.fileOwner) {
                    if (polySocketData.r1 != null) {
                        r1 = polySocketData.r1;
                        Server.receiveR(r1);
                    }
                }
                if(polySocketData.requester){
                    //收到r1和b后，生成Rkab
                    if (polySocketData.b != null) {
                        b = polySocketData.b;
                        Server.receiveB(b);
                        // Server.Rkab 已经生成
                        Rkab = Server.Rkab;
                        System.out.println("RKab已经生成 "+Rkab);

                        /**
                         * 服务器的重代理密钥已经生成
                         * 1. 通知文件拥有者，它可以发送CA了
                         */
                        if(Rkab!=null){
                            noticeFileOwner2sendCA(polySocketData);
                        }
                    }

                }
            }
            return;
        }
        /**
         * 加密解密部分
         * 1. 文件拥有者将明文转换成CA，这一步在文件拥有者发出r后立即进行
         * 2. 服务器将CA转成CB
         */
        if (polySocketData.encry) {
            //文件拥有者生成CA发给服务器
            if(UserA!=null){
                if(polySocketData.fileServer && polySocketData.RkabFinish){
                    //通过文件的名字找出该文件的对称密钥
                    System.out.println("通知我生成CA");
                    String key = SearchFileKey.findKey(polySocketData.fileName);
                    CA = UserA.generateCA(key);
                    if(CA!=null) {
                        System.out.println("文件拥有者已经生成了CA "+CA);
                        System.out.println("shudao: "+polySocketData);
                        sendCA2Server(polySocketData);
                    }
                }
            }

            if(Server!=null) {
                if (polySocketData.fileOwner && polySocketData.CA != null) {
                    CA = polySocketData.CA;
                    CB = Server.CA2CB(CA);
                    /**
                     * 在此时输出CB即可，后续的处理稍后再进行
                     */
                    System.out.println("CB已经生成" + CB);
                }
                /*//把CB给文件的请求者
                if(polySocketData.requester){

                }*/
            }
        }
    }
    /**
     * 文件拥有者的操作
     *
     * @param a  发给request
     * @param r1 发给服务器
     */
    public void sendAR1(PolySocketData polySocketData, IntegerPolynomial a, IntegerPolynomial r1) throws IOException {

        //发送a给request
        ObjectOutputStream os = null;
        os = new ObjectOutputStream(socketOfRequest.getOutputStream());
        PolySocketData polySocketData1 = new PolySocketData(polySocketData, true, a, null);
        os.writeObject(polySocketData1);
        if (os != null) {
            os.close();
        }
        /*if (socketOfRequest != null) {
            socketOfRequest.close();
        }*/

        //把r1发给服务器
        ObjectOutputStream os2 = null;
        Socket socket = new Socket(IpPort.ServerIP, IpPort.ServerPort);
        os2 = new ObjectOutputStream(socket.getOutputStream());
        PolySocketData polySocketData2 = new PolySocketData(polySocketData, true, null, r1);
        polySocketData2.keyExchange = true;
        os2.writeObject(polySocketData2);
        if (os2 != null) {
            os.close();
        }
        if (socket != null) {
            socket.close();
        }
    }
    /**
     * 将一个多项式发送给服务器后，断开socket
     */
    public void RequesterSend2Server(PolySocketData polySocketData, IntegerPolynomial p) throws IOException {
        System.out.println("文件请求者准备发往服务器的数据");
        Socket socket = new Socket(IpPort.ServerIP, IpPort.ServerPort);
        PolySocketData polySocketData2 = new PolySocketData(polySocketData, true, p);
        ObjectOutputStream os = null;
        os = new ObjectOutputStream(socket.getOutputStream());
        os.writeObject(polySocketData2);
        os.close();
        socket.close();
    }
    public void noticeFileOwner2sendCA(PolySocketData polySocketData){
        ObjectOutputStream os = null;
        Socket socket = null;
        try {
            socket = new Socket(IpPort.FileOwnerIP, IpPort.FileOwnerPort);
            PolySocketData polySocketData2 = new PolySocketData(polySocketData);
            polySocketData2.fileServer = true;
            polySocketData2.RkabFinish = true;
            polySocketData2.encry = true;
            os =  new ObjectOutputStream(socket.getOutputStream());
            os.writeObject(polySocketData2);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public void sendCA2Server(PolySocketData polySocketData){
        ObjectOutputStream os = null;
        Socket socket = null;
        try {
            socket = new Socket(IpPort.ServerIP, IpPort.ServerPort);
            System.out.println("文件拥有者收到的 " + polySocketData);
            PolySocketData polySocketData2 = new PolySocketData(polySocketData);
            polySocketData2.fileOwner = true;
            polySocketData2.encry = true;
            polySocketData2.CA = CA;
            os =  new ObjectOutputStream(socket.getOutputStream());
            os.writeObject(polySocketData2);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Override
    public String toString() {
        return "ProxyProcess{" +
                "a=" + a +
                ", r1=" + r1 +
                ", b=" + b +
                ", Rkab=" + Rkab +
                ", CA=" + CA +
                ", CB=" + CB +
                ", keyExchange=" + keyExchange +
                ", encry=" + encry +
                ", UserA=" + UserA +
                ", UserB=" + UserB +
                ", Server=" + Server +
                '}';
    }
}
